package cn.sskxyz.mongodb.zlib;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.zip.Deflater;
import java.util.zip.DeflaterInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

import org.apache.commons.codec.binary.Base64InputStream;
import org.apache.commons.codec.binary.Base64OutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.WriterOutputStream;

import com.fasterxml.jackson.core.io.SegmentedStringWriter;
import com.fasterxml.jackson.core.util.BufferRecycler;
import com.fasterxml.jackson.core.util.ByteArrayBuilder;

public class ZlibCodec implements Codec {

	@Override
	public String compress(byte[] content) {
		Deflater deflater = new Deflater();
		deflater.setInput(content);
		deflater.finish();

		ByteArrayBuilder bos = new ByteArrayBuilder(new BufferRecycler());
		byte[] buf = new byte[4096];
		int len = 0;
		while ((len = deflater.deflate(buf)) != 0) {
			bos.write(buf, 0, len);
		}
		deflater.end();
		byte[] result = bos.toByteArray();
		bos.release();
		return Base64.getEncoder().encodeToString(result);
	}

	@Override
	public String compressToBase64String(InputStream in) {
		DeflaterInputStream dis = new DeflaterInputStream(in, new Deflater(), 8192);

		SegmentedStringWriter sw = new SegmentedStringWriter(new BufferRecycler());
		WriterOutputStream writerOut = new WriterOutputStream(sw, StandardCharsets.US_ASCII);
		Base64OutputStream bos = new Base64OutputStream(writerOut);
		try {
			dis.transferTo(bos);
		} catch (IOException e) {
			throw new RuntimeException("压缩数据异常", e);
		} finally {
			IOUtils.closeQuietly(bos);
		}
		return sw.getAndClear();
	}

	@Override
	public InputStream compressToBase64Stream(InputStream in) {
		DeflaterInputStream dis = new DeflaterInputStream(in, new Deflater(), 8192);
		Base64InputStream bis = new Base64InputStream(dis, true);
		return bis;
	}

	@Override
	public byte[] decompress(byte[] data) {
		try {
			Inflater inflater = new Inflater();
			inflater.setInput(data);
			inflater.finished();

			ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
			byte[] buf = new byte[4096];
			int len = 0;
			while ((len = inflater.inflate(buf)) != 0) {
				bos.write(buf, 0, len);
			}
			inflater.end();
			return bos.toByteArray();
		} catch (Exception e) {
			throw new RuntimeException("解压缩数据异常", e);
		}
	}

	@Override
	public InputStream decompressToStream(byte[] data) {
		ByteArrayInputStream bis = new ByteArrayInputStream(data);
		InflaterInputStream iis = new InflaterInputStream(bis, new Inflater(), 65536);
		return iis;
	}
}
